AWS IoT JSON形式のテンプレートを使ってデバイスを自動登録する (Just-in-Time Provisioning)
こんにちは、hagiwaraです。 AWS IoTでデバイス(モノ)を初回接続時に自動登録することができます。その方法が2種類あります。Just-in-Time Registration (JITR)とJust-in-Time Provisioning (JITP)です。今回は後者のJITPを試してみました。 前者のJITRについては、高橋さんのブログを参照してください。
AWS IoTを使用しているので「デバイス」ではなく「モノ」という単語を使うべきとも思いましたが、個人的に「モノ」が脳内でゲシュタルト崩壊?してしまったので、「デバイス」で統一しています。
JITRとJITPの違い
両者の異なる点は、デバイスをAWS Lambdaを使用して登録するのか、JSON形式のプロビジョニング用テンプレートを元に登録するのかという点です。CA証明書および検証用証明書をAWSに設定する点は同じです。
上の図は、オフィシャルブログに記載されているものを元に記載しました。 どちらを採用するかの判断は、Lambdaで細かいカスタマイズをする必要がある場合はJITR、テンプレートで事足りる場合はJITPといった感じでしょうか。
セットアップ
JITPの設定を行なっていきます。
1. 独自のCA証明書および検証用証明書の作成
ここは、JITRと同様です。
1-1 CA証明書作成
# キーペア作成 openssl genrsa -out rootCA.key 2048 # 証明書作成 CA_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=MyOU/CN=RootCA" openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem -subj "$CA_SUBJ"
1-2 検証用証明書作成
# キーペア作成 openssl genrsa -out verificationCert.key 2048 # AWS IoTのユーザーCA登録コード取得 CODE=`aws iot get-registration-code --output text` # コモンネームに登録コードを設定してCSRを作成 VC_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=verification/CN=${CODE}" openssl req -new -key verificationCert.key -out verificationCert.csr -subj "$VC_SUBJ" # 証明書を作成 openssl x509 -req -in verificationCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out verificationCert.pem -days 500 -sha256
2. デバイスを自動登録するロールの作成
JITPを行うIAM Roleを作成します。
2-1 IAM ロール一覧
IAM の画面から [ロールの作成] を選択。
2-2 信頼されたエンティティの種類およびユースケースの選択
信頼されたエンティティはAWSサービス、ユースケースにIoTを選択して次へ。
2-3 アクセス権限
必要に応じアクセス権限の境界を設定しますが、今回はなにもせずデフォルトのまま次へ。
2-4 タグ
お好みでタグを追加し次へ。
2-5 確認
ロール名を入力し作成。今回はJITPRole
という名前にしました。
3. デバイスにアタッチするポリシーの作成
テンプレートからポリシーを作成することも可能ですが、そうするとデバイスごとに別のポリシーが作成されてしまいます。今回は共通で使用するポリシーをあらかじめ作成しておきます。
AWS IoT Coreコンソール画面をブラウザで開き、[安全性] → [ポリシー] → [作成] → [アドバンストモード] を選択し、以下を入力して作成しました。
名前 :
jitp-things-policy
ステートメント :
{ "Version": "2012-10-17", "Statement": [ { "Action": "iot:Connect", "Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:client/${iot:Connection.Thing.ThingName}", "Effect": "Allow" }, { "Action": [ "iot:Publish", "iot:Receive" ], "Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:topic/$aws/things/${iot:Connection.Thing.ThingName}/shadow/*", "Effect": "Allow" }, { "Action": "iot:Subscribe", "Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:topicfilter/$aws/things/${iot:Connection.Thing.ThingName}/shadow/*", "Effect": "Allow" } ] }
4. テンプレートの作成
4-1 プロビジョニングの設定をテンプレートに記述
以下のようなテンプレートを作成しました。
パラメータの内容についてこちらを参照してください。ポイントはThingName
にデバイス証明書のコモンネームを代入している点と、先ほど作成したポリシーを指定しているところです。
今回は設定していませんが、タイプやグループも指定可能です。その場合はあらかじめそれらを作成しておく必要があります。
{ "Parameters": { "AWS::IoT::Certificate::CommonName": { "Type": "String" }, "AWS::IoT::Certificate::Country": { "Type": "String" }, "AWS::IoT::Certificate::Id": { "Type": "String" } }, "Resources": { "thing": { "Type": "AWS::IoT::Thing", "Properties": { "ThingName": { "Ref": "AWS::IoT::Certificate::CommonName" }, "AttributePayload": { "version": "v1", "country": { "Ref": "AWS::IoT::Certificate::Country" } } } }, "certificate": { "Type": "AWS::IoT::Certificate", "Properties": { "CertificateId": { "Ref": "AWS::IoT::Certificate::Id" }, "Status": "ACTIVE" } }, "policy": { "Type": "AWS::IoT::Policy", "Properties": { "PolicyName": "jitp-things-policy" } } } }
4-2 テンプレートとロールを統合
上記テンプレートを文字列にしてtemplateBody
に、先ほど作成したロールをroleArn
に設定したファイルを作成します。今回はprovisioning-template.json
という名前で作成しました。
{ "templateBody": "{\"Parameters\":{\"AWS::IoT::Certificate::CommonName\":{\"Type\":\"String\"},\"AWS::IoT::Certificate::Country\":{\"Type\":\"String\"},\"AWS::IoT::Certificate::Id\":{\"Type\":\"String\"}},\"Resources\":{\"thing\":{\"Type\":\"AWS::IoT::Thing\",\"Properties\":{\"ThingName\":{\"Ref\":\"AWS::IoT::Certificate::CommonName\"},\"AttributePayload\":{\"version\":\"v1\",\"country\":{\"Ref\":\"AWS::IoT::Certificate::Country\"}}}},\"certificate\":{\"Type\":\"AWS::IoT::Certificate\",\"Properties\":{\"CertificateId\":{\"Ref\":\"AWS::IoT::Certificate::Id\"},\"Status\":\"ACTIVE\"}},\"policy\":{\"Type\":\"AWS::IoT::Policy\",\"Properties\":{\"PolicyName\":\"jitp-things-policy\"}}}}", "roleArn": "arn:aws:iam::<アカウントID>:role/JITPRole" }
JSON→文字列の変換は、ブラウザのコンソールから雑に...
JSON.stringify({templateBody:JSON.stringify(JSON.parse(`<ここにコピペ>`))})
5. CA証明書およびテンプレートの登録
上記で作成したCAを登録し、自動登録の設定を追加します。
# AWSに独自CA証明書を登録 aws iot register-ca-certificate --ca-certificate file://rootCA.pem --verification-cert file://verificationCert.pem # 以下、上記で返却される証明書ID(certificateId)を使用 # 登録した証明書をアクティブに変更 aws iot update-ca-certificate --certificate-id <証明書ID> --new-status ACTIVE # テンプレートを指定して自動登録を有効化 aws iot update-ca-certificate --certificate-id <証明書ID> --new-auto-registration-status ENABLE --registration-config file://provisioning-template.json
以上で設定は終了です、次はデバイスの登録を行なっていきます。
デバイスを接続する
先ほど作成した独自のCA証明書から、デバイスごとにデバイス証明書を作成し、それを使用して接続します。 AWS IoT は登録されていない証明書でのアクセスがあった場合、その証明書を検証します。登録されたCAに基づくものであれば、自動で証明書の登録を行い、テンプレートの内容に従ってデバイスの登録を行います。
1. デバイスごとにデバイス証明書を作成
MyJITPThing
という名前にして証明書を作成しました。接続に使用する証明書にはCA証明書を含める必要があるので、デバイス証明書とCA証明書を統合します。
# 名前 THING_NAME="MyJITPThing" # キーペア作成 openssl genrsa -out deviceCert.key 2048 # コモンネームに名前を設定してCSRを作成 DE_SUBJ="/C=JP/ST=Tokyo/L=Tokyo/O=MyOrg/OU=device/CN=${THING_NAME}" openssl req -new -key deviceCert.key -out deviceCert.csr -subj "$DE_SUBJ" # 証明書作成 openssl x509 -req -in deviceCert.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out deviceCert.crt -days 365 -sha256 # デバイス証明書とCA証明書を統合 cat deviceCert.crt rootCA.pem > deviceCertAndCACert.crt
2. AWSサーバー接続用の証明書を取得
AWSサーバー認証用の証明書をダウンロードしておきます。AWS ドキュメント
curl https://www.amazontrust.com/repository/AmazonRootCA1.pem > root.cert
3. AWS IoT に接続する
mosquitto_sub
を使って未登録の証明書で接続してみます。
END_POINT=`aws iot describe-endpoint --endpoint-type iot:Data-ATS --output text` mosquitto_sub --cafile root.cert \ --cert deviceCertAndCACert.crt \ --key deviceCert.key \ -h $END_POINT \ -p 8883 \ -q 1 \ -i MyJITPThing \ --tls-version tlsv1.2 \ -t '$aws/things/MyJITPThing/shadow/update/delta' \ -d
以下のような感じで出力されました、無事接続はできてそうです。
$ mosquitto_sub --cafile root.cert --cert deviceCertAndCACert.crt --key deviceCert.key -h $END_POINT -p 8883 -q 1 -i MyJITPThing --tls-version tlsv1.2 -t '$aws/things/MyJITPThing/shadow/update/delta' -d Client MyJITPThing sending CONNECT Client MyJITPThing sending CONNECT Client MyJITPThing sending CONNECT Client MyJITPThing sending CONNECT Client MyJITPThing sending CONNECT
3. 確認
コンソールからも無事登録されてることが確認できました!
記載はしていませんが、詳細画面から自動登録された証明書と、前もって作成しておいたポリシーがアタッチされていることが確認できます。
まとめ
以上、テンプレートを使用したデバイス登録を試してみました。デバイス登録時の設定がテンプレートで事足りる場合は、Lambdaを実装しなくていいのでこちらのほうがよさそうです。
参考 URL
ジャストインタイムのプロビジョニング Setting Up Just-in-Time Provisioning with AWS IoT Core AWS IoTの証明書自動登録でクライアント証明書の運用を楽にする